#pragma once

#include "event/cabinet.hpp"
#include "event/loop.hpp"
#include "network/buffer.hpp"
#include "network/sockaddr.hpp"
#include "network/tcp_connection.hpp"

namespace ibox::network {
using ConnToken = cabinet::Token;

class TcpServer {
    using ConnectedCallback = std::function<void(const ConnToken *)>;
    using DisconnectedCallback = std::function<void(const ConnToken *)>;
    using ReceiveCallback = std::function<void(const ConnToken *, Buffer &)>;

public:
    explicit TcpServer(event::Loop *loop);
    ~TcpServer();

public:
    enum class State {
        None,
        Inited,
        Running,
    };

    // 设置绑定地址与backlog
    bool initialize(const SockAddr &bind_address, int listen_backlog);

    // 设置有新客户端连接时的回调
    void set_connected_callback(ConnectedCallback cb);
    // 设置有客户端断开时的回调
    void set_disconnected_callback(DisconnectedCallback cb);
    // 设置接收到客户端消息时的回调
    void set_receive_callback(ReceiveCallback cb, size_t threshold);

    // 启动服务
    bool start();
    // 停止服务, 断开所有连接
    void stop();
    // 清理
    void cleanup();

    // 向指定客户端发送数据
    bool send(const ConnToken *conn, const void *data_ptr, size_t data_size);
    // 断开指定客户端的连接
    bool disconnect(const ConnToken *conn);
    // 半关闭
    bool shutdown(const ConnToken *conn, int howto);
    // 检查客户端的连接是否有效
    bool is_client_valid(const ConnToken *conn) const;
    // 获取客户端的地址
    const SockAddr *get_client_address(const ConnToken *conn) const;

    // 设置上下文
    void *set_context(const ConnToken *conn, void *context);
    // 获取上下文
    void *get_context(const ConnToken *conn) const;

    State state() const;

private:
    void on_tcp_connected(TcpConnection *new_conn);
    void on_tcp_disconnected(const ConnToken *conn);
    void on_tcp_received(const ConnToken *conn, Buffer &buff);

private:
    struct Data;
    std::unique_ptr<Data> m_data{};
};
} // namespace ibox::network
